home *** CD-ROM | disk | FTP | other *** search
/ Aminet 32 / Aminet 32 (1999)(Schatztruhe)[!][Aug 1999].iso / Aminet / dev / lang / Python151.lha / Python-1.5 / Lib / Python1.5 / multifile.py < prev    next >
Text File  |  1998-03-26  |  3KB  |  138 lines

  1. # A class that makes each part of a multipart message "feel" like an
  2. # ordinary file, as long as you use fp.readline().  Allows recursive
  3. # use, for nested multipart messages.  Probably best used together
  4. # with module mimetools.
  5. #
  6. # Suggested use:
  7. #
  8. # real_fp = open(...)
  9. # fp = MultiFile(real_fp)
  10. #
  11. # "read some lines from fp"
  12. # fp.push(separator)
  13. # while 1:
  14. #    "read lines from fp until it returns an empty string" (A)
  15. #    if not fp.next(): break
  16. # fp.pop()
  17. # "read remaining lines from fp until it returns an empty string"
  18. #
  19. # The latter sequence may be used recursively at (A).
  20. # It is also allowed to use multiple push()...pop() sequences.
  21. # Note that if a nested multipart message is terminated by a separator
  22. # for an outer message, this is not reported, even though it is really
  23. # illegal input.
  24.  
  25. import sys
  26. import string
  27.  
  28. err = sys.stderr.write
  29.  
  30. Error = 'multifile.Error'
  31.  
  32. class MultiFile:
  33.     #
  34.     def __init__(self, fp):
  35.         self.fp = fp
  36.         self.stack = [] # Grows down
  37.         self.level = 0
  38.         self.last = 0
  39.         self.start = self.fp.tell()
  40.         self.posstack = [] # Grows down
  41.     #
  42.     def tell(self):
  43.         if self.level > 0:
  44.             return self.lastpos
  45.         return self.fp.tell() - self.start
  46.     #
  47.     def seek(self, pos, whence=0):
  48.         here = self.tell()
  49.         if whence:
  50.             if whence == 1:
  51.                 pos = pos + here
  52.             elif whence == 2:
  53.                 if self.level > 0:
  54.                     pos = pos + self.lastpos
  55.                 else:
  56.                     raise Error, "can't use whence=2 yet"
  57.         if not 0 <= pos <= here or \
  58.                 self.level > 0 and pos > self.lastpos:
  59.             raise Error, 'bad MultiFile.seek() call'
  60.         self.fp.seek(pos + self.start)
  61.         self.level = 0
  62.         self.last = 0
  63.     #
  64.     def readline(self):
  65.         if self.level > 0: return ''
  66.         line = self.fp.readline()
  67.         if not line:
  68.             self.level = len(self.stack)
  69.             self.last = (self.level > 0)
  70.             if self.last:
  71.                 err('*** Sudden EOF in MultiFile.readline()\n')
  72.             return ''
  73.         if line[:2] <> '--': return line
  74.         n = len(line)
  75.         k = n
  76.         while k > 0 and line[k-1] in string.whitespace: k = k-1
  77.         mark = line[2:k]
  78.         if mark[-2:] == '--': mark1 = mark[:-2]
  79.         else: mark1 = None
  80.         for i in range(len(self.stack)):
  81.             sep = self.stack[i]
  82.             if sep == mark:
  83.                 self.last = 0
  84.                 break
  85.             elif mark1 <> None and sep == mark1:
  86.                 self.last = 1
  87.                 break
  88.         else:
  89.             return line
  90.         # Get here after break out of loop
  91.         self.lastpos = self.tell() - len(line)
  92.         self.level = i+1
  93.         if self.level > 1:
  94.             err('*** Missing endmarker in MultiFile.readline()\n')
  95.         return ''
  96.     #
  97.     def readlines(self):
  98.         list = []
  99.         while 1:
  100.             line = self.readline()
  101.             if not line: break
  102.             list.append(line)
  103.         return list
  104.     #
  105.     def read(self): # Note: no size argument -- read until EOF only!
  106.         return string.joinfields(self.readlines(), '')
  107.     #
  108.     def next(self):
  109.         while self.readline(): pass
  110.         if self.level > 1 or self.last:
  111.             return 0
  112.         self.level = 0
  113.         self.last = 0
  114.         self.start = self.fp.tell()
  115.         return 1
  116.     #
  117.     def push(self, sep):
  118.         if self.level > 0:
  119.             raise Error, 'bad MultiFile.push() call'
  120.         self.stack.insert(0, sep)
  121.         self.posstack.insert(0, self.start)
  122.         self.start = self.fp.tell()
  123.     #
  124.     def pop(self):
  125.         if self.stack == []:
  126.             raise Error, 'bad MultiFile.pop() call'
  127.         if self.level <= 1:
  128.             self.last = 0
  129.         else:
  130.             abslastpos = self.lastpos + self.start
  131.         self.level = max(0, self.level - 1)
  132.         del self.stack[0]
  133.         self.start = self.posstack[0]
  134.         del self.posstack[0]
  135.         if self.level > 0:
  136.             self.lastpos = abslastpos - self.start
  137.     #
  138.